package util.sharedmemory;

import static org.junit.Assert.*;

import java.io.File;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class SharedMemoryTester {
	static final int SM_SIZE = 10;
	static private String smLocation;
	static private SharedMemory sm;
	
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		// Create a new shared memory segment
		int randNum = (int)(Math.random() * 10000);
		smLocation = "/testSM" + randNum;
		sm = new SharedMemory(smLocation, SM_SIZE, true);
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
		sm.destroy();
	}

	@Before
	public void setUp() throws Exception {
	}

	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void testCreationAndRemoval() {
		try {
			// Create a new shared memory segment
			int randNum = (int)(Math.random() * 10000);
			String location = "/testSM" + randNum;
			SharedMemory mySm = new SharedMemory(location, 2, true);

			// Verification - if it failed, it will throw an exception
			/*
			// Verify it was created
			File f = new File(location);
			if (!f.exists()) {
				fail("File " + location + " does not exist (failed to create)");
			}
			*/
			
			// Remove the shared memory segment
			mySm.destroy();

		} catch (Exception ex) {
			fail("Exception was thrown: " + ex.getMessage());
		}
	}

	@Test
	public void testRemoval() {
		try {
			// Create a new shared memory segment
			int randNum = (int)(Math.random() * 10000);
			String location = "/testSM" + randNum;
			SharedMemory mySm = new SharedMemory(location, 2, true);
			
			// Verification - if it failed, it will throw an exception
			/*
			// Verify it was created
			File f = new File(location);
			if (!f.exists()) {
				fail("File " + location + " does not exist (failed to create)");
			}
			*/
			
			// Remove the shared memory segment
			mySm.destroy();
			
			// Verification - if it failed, it will throw an exception
			/*
			// Verify it was removed
			File f2 = new File(location);
			if (!f2.exists()) {
				fail("File " + location + " exists after removal (failed to destroy)");
			}
			*/

		} catch (Exception ex) {
			fail("Exception was thrown: " + ex.getMessage());
		}
	}

	
	@Test
	public void testOpen() {
		try {
			// Try to attach to a current shared-memory segment
			SharedMemory mySm = new SharedMemory(smLocation, SM_SIZE, false);
			
			
			// close the shared memory segment
			mySm.close();
			
		} catch (Exception ex) {
			fail("Exception was thrown: " + ex.getMessage());
		}
	}

	@Test
	public void testClose() {
		try {
			// Try to attach to a current shared-memory segment
			SharedMemory mySm = new SharedMemory(smLocation, SM_SIZE, false);
			
			
			// close the shared memory segment
			mySm.close();
			
		} catch (Exception ex) {
			fail("Exception was thrown: " + ex.getMessage());
		}
	}


	@Test
	public void testWriteRead() {
		try {
			// Try to attach to a current shared-memory segment
			SharedMemory mySm = new SharedMemory(smLocation, SM_SIZE, false);
			final byte myChar = (byte)('A' + (int)(Math.random() * ('Z' - 'A')));
			
			final byte[] writeBuf = new byte[1];
			writeBuf[0] = myChar;
			
			// Write to that shared memory segment
			mySm.write(writeBuf, 0, 1, 0);

			byte[] readBuf = new byte[1];
			mySm.read(0, readBuf, 0, 1);
			
			assertTrue(myChar == readBuf[0]);
			
			// close the shared memory segment
			mySm.close();
			
		} catch (Exception ex) {
			fail("Exception was thrown: " + ex.getMessage());
		}
	}

	@Test
	public void testWriteReadArray() {
		try {
			// Try to attach to a current shared-memory segment
			SharedMemory mySm = new SharedMemory(smLocation, SM_SIZE, false);
			
			final byte[] writeBuf = new byte[SM_SIZE];
			for (int i = 0; i < SM_SIZE; i++) {
				final byte myChar = (byte)('A' + (int)(Math.random() * ('Z' - 'A')));
				writeBuf[i] = myChar;
			}
			
			// Write to that shared memory segment
			mySm.write(writeBuf, 0, SM_SIZE, 0);

			byte[] readBuf = new byte[SM_SIZE];
			mySm.read(0, readBuf, 0, SM_SIZE);

			for (int i = 0; i < SM_SIZE; i++) {
				assertTrue(writeBuf[i] == readBuf[i]);
			}
			
			// close the shared memory segment
			mySm.close();
			
		} catch (Exception ex) {
			fail("Exception was thrown: " + ex.getMessage());
		}
	}

	@Test
	public void testWriteReadArrayBufOffset() {
		try {
			// Try to attach to a current shared-memory segment
			SharedMemory mySm = new SharedMemory(smLocation, SM_SIZE, false);
			final int diffSize = 3;
			
			final byte[] writeBuf = new byte[SM_SIZE];
			for (int i = diffSize; i < SM_SIZE; i++) {
				final byte myChar = (byte)('A' + (int)(Math.random() * ('Z' - 'A')));
				writeBuf[i] = myChar;
			}
			
			// Write to that shared memory segment
			mySm.write(writeBuf, diffSize, SM_SIZE - diffSize, 0);

			byte[] readBuf = new byte[SM_SIZE];
			mySm.read(0, readBuf, diffSize, SM_SIZE - diffSize);

			for (int i = diffSize; i < SM_SIZE; i++) {
				assertTrue(writeBuf[i] == readBuf[i]);
			}
			
			// close the shared memory segment
			mySm.close();
			
		} catch (Exception ex) {
			fail("Exception was thrown: " + ex.getMessage());
		}
	}


	@Test
	public void testWriteReadArraySegmentOffset() {
		try {
			// Try to attach to a current shared-memory segment
			SharedMemory mySm = new SharedMemory(smLocation, SM_SIZE, false);
			final int diffSize = 3;
			
			final byte[] writeBuf = new byte[SM_SIZE];
			for (int i = 0; i < SM_SIZE; i++) {
				final byte myChar = (byte)('A' + (int)(Math.random() * ('Z' - 'A')));
				writeBuf[i] = myChar;
			}
			
			// Write to that shared memory segment
			mySm.write(writeBuf, 0, SM_SIZE - diffSize, diffSize);

			byte[] readBuf = new byte[SM_SIZE];
			mySm.read(diffSize, readBuf, 0, SM_SIZE - diffSize);

			for (int i = 0; i < SM_SIZE - diffSize; i++) {
				assertTrue(writeBuf[i] == readBuf[i]);
			}
			
			// close the shared memory segment
			mySm.close();
			
		} catch (Exception ex) {
			fail("Exception was thrown: " + ex.getMessage());
		}
	}

}
